package com.flink.datastreamapi.sink;

import org.apache.flink.connector.base.DeliveryGuarantee;
import org.apache.flink.connector.kafka.sink.KafkaRecordSerializationSchema;
import org.apache.flink.connector.kafka.sink.KafkaSink;
import org.apache.flink.streaming.api.CheckpointingMode;
import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.kafka.clients.producer.ProducerConfig;
import org.apache.kafka.clients.producer.ProducerRecord;

import javax.annotation.Nullable;
import java.nio.charset.StandardCharsets;

public class KafkaSinkCustomKeyDemo {

    public static void main(String[] args) throws Exception {

        //获取环境
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        //设置并行度
        env.setParallelism(1);
        //如果是精准一次，必须开启checkpoint
        env.enableCheckpointing(2000, CheckpointingMode.EXACTLY_ONCE);

        SingleOutputStreamOperator<String> sensorDS = env
                //读取socket
                .socketTextStream("node2", 8888);


/**
 * 如果要指定写入kafka的key，可以自定义序列化器：
 * 1、实现 一个接口，重写 序列化 方法
 * 2、指定key，转成 字节数组
 * 3、指定value，转成 字节数组
 * 4、返回一个 ProducerRecord对象，把key、value放进去
 */
        //输出到Kafka
        KafkaSink<String> kafkaSink = KafkaSink.<String>builder()
                //kafka的地址和端口
                .setBootstrapServers("node1:9092,node2:9092,node3:9092")
                //指定序列化器：指定Topic名称、具体的序列化
                .setRecordSerializer(
                        //自定义系列化器
                        new KafkaRecordSerializationSchema<String>() {
                            @Nullable
                            @Override
                            public ProducerRecord<byte[], byte[]> serialize(String element, KafkaSinkContext context, Long timestamp) {
                                String[] datas = element.split(",");
                                byte[] key = datas[0].getBytes(StandardCharsets.UTF_8);
                                byte[] value = element.getBytes(StandardCharsets.UTF_8);
                                return new ProducerRecord<>("my_topic",key,value);
                            }
                        }
                )
                //写到kafka的一致性级别：精准一次，至少一次
                .setDeliveryGuarantee(DeliveryGuarantee.EXACTLY_ONCE)
                //如果是精准一次，必须设置 事务的前缀
                .setTransactionalIdPrefix("flink-")
                //如果是精准一次，必须设置 事务超时时间 大于checkpoint间隔，小于max 15分钟
                .setProperty(ProducerConfig.TRANSACTION_TIMEOUT_CONFIG,10*60*1000+"")
                .build();

        //设置sink目的地
        sensorDS.sinkTo(kafkaSink);
        //执行
        env.execute();

    }
}
